package roborally;


import java.awt.IllegalComponentStateException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;

import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;

import roborally.*;
import roborally.Conditions.Condition;


/**
 * A class of boards, extending terminateable, for playing the roborally game, involving a width, height and all objects on the board.
 * 
 * @invar  | isValidWidth(this.getWidth())
 * @invar  | isValidHeight(this.getHeight())
 * 
 * @version  2.90
 * @author   Michiel Ruelens & Dieter Naten
 */

@SuppressWarnings("unchecked")
public class Board extends Terminateable {

	private final long width;
	private final long height;
	private static final long widthUpperBound = Long.MAX_VALUE;
	private static final long heightUpperBound = Long.MAX_VALUE;
	private HashMap<Coordinate,Set<? extends Placeable>> allObjectsByPosition;
	private HashMap<PlaceableType,Set<? extends Placeable>> allObjectsByType;
	
	/**
     * Initialize the new board with the given parameters.
     * 
     * @param  	width
     * 		   	The width of the new board.
     * @param  	height
     * 		   	The height of the new board.
     * @post 	| (new this).getWidth() == width
     * @post 	| (new this).getHeight() == height
	 * @throws	IllegalArgumentException()
	 * 			| if(!isValidWidth(width) || !isValidHeight(height))
     */
	@Raw
	public Board(long width, long height) throws IllegalArgumentException{
		super();
		if(!isValidWidth(width) || !isValidHeight(height)){
			System.out.println("The given width and/or height aren't valid");
			throw new IllegalArgumentException();
		}
		this.width = width;
		this.height = height;
		allObjectsByPosition = new HashMap<Coordinate,Set<? extends Placeable>>();
		allObjectsByType = new HashMap<PlaceableType,Set<? extends Placeable>>();
	}
	
	/**
	 * This method will return the width of the board.
	 */
	@Basic
	public long getWidth() {
		return width;
	}
	
	/**
     * Check if the given width is valid for a board.
     *  
     * @param  	width
     * 		   	The width you want to check.
     * @return 	| result ==
     *       	| (width>0 && width<=widthUpperBound)	
     */
	public static boolean isValidWidth(long width) {
		return (width>=0 && width<=widthUpperBound);
	}

	/**
	 * This method will return the height of the board.
	 */
	@Basic
	public long getHeight() {
		return height;
	}

	/**
     * Check if the given height is valid for a board.
     *  
     * @param  	height
     * 		   	The height you want to check.
     * @return 	| result ==
     *       	| (height>0 && height<=heightUpperBound)	
     */
	public static boolean isValidHeight(long height) {
		return (height>=0 && height<=heightUpperBound);
	}

	/**
	 * This method will return the maxWidth of the board.
	 */
	@Basic
	public long getMaxWidth(){
		return widthUpperBound;
	}

	/**
	 * This method will return the maxHeight of the board.
	 */
	@Basic
	public long getMaxHeight(){
		return heightUpperBound;
	}
	
	/**
	 * Terminates this board and all placeables it contains.
	 * 
	 * @effect	| for(placeable p: this.getAllObjectsOnThisBoard())
	 * 			|		p.terminate()
	 * @effect	| this.clearBoard()
	 * @effect	| super.terminate()
	 */
	@Override
	public void terminate(){
		List<Placeable> allObjects = this.getAllObjectsOnThisBoard();
		if(!allObjects.isEmpty()){
			for(Placeable p: allObjects){
				p.terminate();
			}
		}
		this.clearBoard();
		super.terminate();
	}
	
	/**
	 * This method will return all the 'placeables' on a certain given position on the board.
	 * 
     * @param  	x
     * 		   	The x-coordinate on which you want to check for placeables.
     * @param  	y
     * 		   	The y-coordinate on which you want to check for placeables.
	 * @return 	All placeables on the specified position
     *       	| for(Coordinate coordinate: coordinateSet)
	 *			| 	if(coordinate.getX()==x && coordinate.getY()==y)
	 *			|		matchingCoordinate = coordinate;
	 *			| --> result == allObjectsByPosition.get(matchingCoordinate)
	 * @throws	IllegalArgumentException()
	 * 			| if(!Coordinate.isValidXCoordinate(this, x)) || !Coordinate.isValidYCoordinate(this, y))
	 */
	public HashSet<Placeable> getAllObjectsByPosition(long x, long y) throws IllegalArgumentException{
		if(!Coordinate.isValidXCoordinate(this, x) && !Coordinate.isValidYCoordinate(this, y)){
			throw new IllegalArgumentException();
		}
		HashSet<Placeable> resultSet = new HashSet<Placeable>();
		Set<Coordinate> coordinateSet = allObjectsByPosition.keySet();
		Coordinate matchingCoordinate = null;
		for(Coordinate coordinate: coordinateSet){
			if(coordinate.getX()==x && coordinate.getY()==y){
				matchingCoordinate = coordinate;
			}
		}
		if(matchingCoordinate!=null){
			resultSet = (HashSet<Placeable>) allObjectsByPosition.get(matchingCoordinate);
		}
		return resultSet;
	}

	/**
	 * This method will return all the 'placeables' of a certain type.
	 * 
     * @param  	type
     * 		  	The type of placeables you want to find.
	 * @return	All placeables of the specified type.
     *       	| result ==
     *       	| allObjectsByType.get(type)
	 */	
	public Set<? extends Placeable> getAllObjectsByType(PlaceableType type) {
		Set<Placeable> resultSet = new HashSet<Placeable>();
		if(allObjectsByType.containsKey(type)){
		resultSet = (Set<Placeable>) allObjectsByType.get(type);
		}
		return (HashSet<Placeable>) resultSet;
	}
	
	/**
	 * This method will add a placeable to the placeable set of the board.
	 * 
     * @param  	placeable
     * 		   	The placeable you want to add to the placeable set of the board
     * @post   	| (new this).getallObjectsByType(placeable.getType()).contains(placeable) == true
     * @post  	| (new this).getallObjectsByPostion(placeable.getX(),placeable.getY()).contains(placeable) == true
	 * @throws	IllegalComponentStateException()
	 * 			| if(placeable.isTerminated() || placeable == null)
	 */
	public void addPlaceable(Placeable placeable) throws IllegalComponentStateException{
		if(placeable.isTerminated() || placeable == null){
			throw new IllegalComponentStateException();
		}
		//add the placeable to the first Set
		Set<Placeable> typeSet1 = new HashSet<Placeable>();	
		if(allObjectsByType.containsKey(placeable.getPlaceableType())){
		typeSet1 = (Set<Placeable>) allObjectsByType.get(placeable.getPlaceableType());
		}
		typeSet1.add(placeable);
		allObjectsByType.put(placeable.getPlaceableType(), typeSet1);
		
		//add the placeable to the second Set
		Set<Placeable> typeSet2 = new HashSet<Placeable>();	
		if(allObjectsByPosition.containsKey(placeable.getCoordinate())){
			typeSet2 = (Set<Placeable>) allObjectsByPosition.get(placeable.getCoordinate());
		}
		typeSet2.add(placeable);
		allObjectsByPosition.put(placeable.getCoordinate(), typeSet2);
	}

	/**
	 * This method will check if their is a placeable at the given position on the board.
	 * 
     * @param  	x
     * 		   	The x-coordinate on which you want to check for placeables.
     * @param  	y
     * 		   	The y-coordinate on which you want to check for placeables.
     * @return 	| result ==
     * 		   	| true
     * 		   	| (if(for(Coordinate coordinates: coordinateSet) &&
	 *		   	|  if(coordinates.getX() == x && coordinates.getY() == y))
	 * @throws	IllegalArgumentException
	 * 			| if(!Coordinate.isValidXCoordinate(this, x) && !Coordinate.isValidYCoordinate(this, y))
	 */	
	public boolean hasPlaceableAtPosition(long x, long y) throws IllegalArgumentException{
		if(!Coordinate.isValidXCoordinate(this, x) && !Coordinate.isValidYCoordinate(this, y)){
			throw new IllegalArgumentException();
		}
		boolean result = false;
		Set<Coordinate> coordinateSet = this.allObjectsByPosition.keySet();
		for(Coordinate coordinates: coordinateSet){
			if(coordinates.getX() == x && coordinates.getY() == y)
			{
				result = true;
			}
		}
		return result;
	}

	/**
	 * This method will shoot a random placeable at a given position on the board.
	 * 
     * @param  	x
     * 		   	The x-coordinate on which you want to destroy a random placeable.
     * @param  	y
     * 		   	The y-coordinate on which you want to destroy a random placeable.
     * @effect  | ArrayList<Placeable>(this.getAllObjectsByPosition(x, y)).get(random.nextInt(placeableArray.size())).hit()
     * @effect  | cleanUpUnusedCoordinates()
	 * @throws	IllegalArgumentException
	 * 			| if(!Coordinate.isValidXCoordinate(this, x) && !Coordinate.isValidYCoordinate(this, y))
	 */	
	public void shootPlaceableAt(long x, long y) throws IllegalArgumentException{
		if(!Coordinate.isValidXCoordinate(this, x) && !Coordinate.isValidYCoordinate(this, y)){
			throw new IllegalArgumentException();
		}
		HashSet<Placeable> placeableSet = this.getAllObjectsByPosition(x, y);
		if(placeableSet == null){ System.out.println("There is nothing to shoot"); }
		else{
			ArrayList<Placeable> placeableArray = new ArrayList<Placeable>(placeableSet);
			Random random = new Random();			
			Placeable placeableToDestroy = placeableArray.get(random.nextInt(placeableArray.size()));
			placeableToDestroy.hit();
			}
		cleanUpUnusedCoordinates();
	}

	/**
	 * This method will remove a given placeable from the board.
	 * 
     * @param  	placeableToRemove
     * 		   	The placeable to remove from the board.
     * @post   	| (new this).getallObjectsByType(placeableToRemove.getType()).contains(placeableToRemove) == false
     * @post   	| (new this).getallObjectsByPostion(placeable.getX(),placeable.getY()).contains(placeable) == false
     * @effect 	| cleanUpUnusedCoordinates()
	 * @throws	IllegalComponentStateException
	 * 			| if(placeableToRemove == null)
	 */	
	public void removePlaceable(Placeable placeableToRemove) throws IllegalComponentStateException{
		if(placeableToRemove == null){
			throw new IllegalComponentStateException();
		}		
		Set<Placeable> typeSet1 = (Set<Placeable>) getAllObjectsByType(placeableToRemove.getPlaceableType());
		typeSet1.remove(placeableToRemove);
		if(typeSet1.isEmpty()){
			allObjectsByType.remove(placeableToRemove.getPlaceableType());
		}
		else{
		allObjectsByType.put(placeableToRemove.getPlaceableType(), typeSet1);
		}
		
		Set<Placeable> typeSet2 = (Set<Placeable>) allObjectsByPosition.get(placeableToRemove.getCoordinate());
		typeSet2.remove(placeableToRemove);
		if(typeSet2.isEmpty()){
			allObjectsByPosition.remove(placeableToRemove.getCoordinate());
		}
		else{
		allObjectsByPosition.put(placeableToRemove.getCoordinate(), typeSet2);
		}
		cleanUpUnusedCoordinates();
	}

	/**
	 * This method will return if there is a wall on a certain given position on the board.
	 * 
     * @param  	x
     * 		   	The x-coordinate on which you want to check for a wall.
     * @param  	y
     * 		   	The y-coordinate on which you want to check for a wall.
	 * @return 	| result ==
     *       	| true
     *       	|  if
     *       	|  	(for(Placeable placeable:getAllObjectsByPosition(x,y))
	 *		 	|			-->	(if(placeable instanceof Wall) && placeable.getX()==x && placeable.getY()==y))
	 * @throws	IllegalArgumentException
	 * 			| if(!Coordinate.isValidXCoordinate(this, x) && !Coordinate.isValidYCoordinate(this, y))
	 */
	public boolean hasWallAtPosition(long x, long y) throws IllegalArgumentException{
		if(!Coordinate.isValidXCoordinate(this, x) || !Coordinate.isValidYCoordinate(this, y)){
			throw new IllegalArgumentException();
		}
		Set<Placeable> placeableSet = getAllObjectsByPosition(x,y);
		boolean result = false;
		if(placeableSet == null || placeableSet.isEmpty()){
		}
		else{
			for(Placeable placeable:placeableSet){
				System.out.println(placeable+" - "+(placeable instanceof Wall)+ " - "+(placeable.getX()==x && placeable.getY()==y));
				if(placeable instanceof Wall){
					if(placeable.getX()==x && placeable.getY()==y){
						result = true;
					}
				}
			}
		}
		return result;	
	}

	/**
	 * This method is used to clean up coordinates that no longer contain any objects on this board.
	 * The board holds all objects sorted per coordinate. If a coordinate used to have objects placed at a certain
	 * coordinate, but for some reason at this point it no longer does, then that coordinate should no longer
	 * be stored, and thus is removed.
	 * 
	 * @post	| For all valid x and y: getAllObjectsByPosition(x,y).isEmpty()==false
	 */
	public void cleanUpUnusedCoordinates(){
		Iterator<Entry<Coordinate, Set<? extends Placeable>>> iter = allObjectsByPosition.entrySet().iterator();
		while (iter.hasNext()) {
		    Entry<Coordinate, Set<? extends Placeable>> entry = iter.next();
		    if(entry.getValue().isEmpty()){
		        iter.remove();
		    }
		}
	}
	
	/**
	 * This method will correct the saved coordinate of a placeable when it moved.
	 * 
     * @param  	placeable
     * 		   	The placable which coordinate should be changed after moving.
     * @param  	oldCoordinate
     * 		   	The old coordinate of the placeable that has moved.
     * @param  	newCoordinate
     * 		   	The new coordinate of the placeable that has moved.
     * @pre		| this.getAllObjectsByPosition(oldCoordinate.getX(),oldCoordinate.getY()).contains(placeable)
	 * @post 	| (new this).getallObjectsByPosition(oldCoordinate.getX(),oldCoordinate.getY()).contains(placeable) == false
	 * @post 	| (new this).getallObjectsByPosition(newCoordinate.getX(),newCoordinate.getY()).contains(placeable) == true
	 * @throws	IllegalArgumentException
	 * 			| OR if(!Coordinate.isValidXCoordinate(this, oldCoordinate.getX()) || !Coordinate.isValidXCoordinate(this, newCoordinate.getX()))
	 * 			| OR if(!Coordinate.isValidYCoordinate(this, oldCoordinate.getY()) || !Coordinate.isValidYCoordinate(this, newCoordinate.getY()))
	 * @throws	IllegalStateException
	 * 			| if(!allObjectsByPosition.containsKey(oldCoordinate))
	 * @throws	IllegalComponentStateException
	 * 			| if(placeable == null)
	 */
	public void updateHashMapByPositionAfterMove(Placeable placeable, Coordinate oldCoordinate, Coordinate newCoordinate) throws IllegalArgumentException, IllegalComponentStateException, IllegalStateException{
		if(!Coordinate.isValidXCoordinate(this, oldCoordinate.getX()) || !Coordinate.isValidXCoordinate(this, newCoordinate.getX())
			|| !Coordinate.isValidYCoordinate(this, oldCoordinate.getY()) || !Coordinate.isValidYCoordinate(this, newCoordinate.getY())){
			throw new IllegalArgumentException();
		}		
		if(!allObjectsByPosition.containsKey(oldCoordinate)){
			throw new IllegalStateException();
		}	
		if(placeable == null){
			throw new IllegalComponentStateException();
		}
		//Remove the placeable from its current position
		Set<? extends Placeable> oldSet = getAllObjectsByPosition(oldCoordinate.getX(),oldCoordinate.getY());
		assert(oldSet.contains(placeable));
		oldSet.remove(placeable);		
		allObjectsByPosition.remove(oldCoordinate);
		allObjectsByPosition.put(oldCoordinate, oldSet);
		cleanUpUnusedCoordinates();
		
		//Put the placeable in its new position
		Set<Placeable> newSet = getAllObjectsByPosition(newCoordinate.getX(),newCoordinate.getY());
		newSet.add(placeable);
		if(allObjectsByPosition.containsKey(newCoordinate)){
			allObjectsByPosition.remove(newCoordinate);
		}
		allObjectsByPosition.put(newCoordinate, newSet);
	}

	/**
	 * This method will clear the board, all placeables that were on the board, will be removed.
	 * 
	 * @post | (new this).allObjectsByPosition().isEmpty() == true
	 * @post | (new this).allObjectsByType().isEmpty() == true
	 */
	public void clearBoard() {
		this.allObjectsByPosition = new HashMap<Coordinate,Set<? extends Placeable>>();
		this.allObjectsByType = new HashMap<PlaceableType,Set<? extends Placeable>>();
	}
	
	/**
	 * This method returns a list containing all the placeables that are currently on this board.
	 * 
	 * @return	A list with all the placeables on this board
	 * 			| for(PlaceableType type : PlaceableType.getAllPlaceableTypes())
	 *			| 	Set<Placeable> objectList = (Set<Placeable>) getAllObjectsByType(type);
	 *			| 	if(!objectList.isEmpty())
	 *			| 		resultList.addAll(objectList);
	 *			| result ==
	 * 			| resultList
	 */
	public List<Placeable> getAllObjectsOnThisBoard(){
		List<Placeable> resultList = new ArrayList<Placeable>();
		List<PlaceableType> placeableTypeList = PlaceableType.getAllPlaceableTypes();
		if(!placeableTypeList.isEmpty()){
			for(PlaceableType type : placeableTypeList){
				Set<Placeable> objectList = (Set<Placeable>) getAllObjectsByType(type);
				if(!objectList.isEmpty()){
					resultList.addAll(objectList);
				}
			}
		}
		return resultList;
	}
	
	/**
	 * This method merges two boards together. All placeables from the second board are moved to this one, if possible.
	 * If that is not possible for a certain placeable because of size limitations or this board has a wall at that position,
	 * said placeable is terminated.
	 * 
	 * @param	otherBoard
	 * 			The other board that is being merged with this one. All placeables are moved from otherBoard to this board.
	 * @post	otherBoard.isTerminated()==true
	 * @post	for(Placeable p:otherBoard().getAllObjectsOnThisBoard())
	 * 				p.isTerminated() ||	this.getAllObjectsOnThisBoard().contains(p)
	 */
	public void merge(Board otherBoard){
		if(!otherBoard.isTerminated() && otherBoard!=null){
			List<Placeable> allObjectsFromOtherBoard = otherBoard.getAllObjectsOnThisBoard();
			if(!allObjectsFromOtherBoard.isEmpty()){
				for(Placeable po:allObjectsFromOtherBoard){
					System.out.println(" 1 other: "+po);
				}
				for(Placeable pt:this.getAllObjectsOnThisBoard()){
					System.out.println(" 1 this: "+pt);
				}
				for(Placeable p:allObjectsFromOtherBoard){
					if(!hasWallAtPosition(p.getX(), p.getY()) && p.getX()<=getWidth() && p.getY()<=getHeight()){
						/*Do not call the methods "this.removePlaceable(p)" and "p.getBoard().removePlaceable(p)"
						*Because These are already done within the method setBoard. Doing so would cause errors.
						*/
						p.getBoard().removePlaceable(p);
						p.setBoard(null);
						p.setBoard(this);
						this.addPlaceable(p);
					}
					else{
						otherBoard.removePlaceable(p);
						p.terminate();
					}
				}
				for(Placeable po:allObjectsFromOtherBoard){
					System.out.println(" 2 other: "+po);
				}
				for(Placeable pt:this.getAllObjectsOnThisBoard()){
					System.out.println(" 2 this: "+pt);
				}
			}
			otherBoard.clearBoard();
			otherBoard.terminate();
		}
		else{
			System.out.println("The board you tried to merge does not exist or is terminated.");
		}
	}	
	
	/**
	 * Returns an iterator, with the given parameters.
	 * 
	 * @param 	condition
	 * 			Condition which the elements should satisfy
	 * @param 	nbOfElements
	 * 			The number of elements you want to get from this iterator
	 * @return	A new iterator satisfying all requestioned parameters.
	 * 			| new Iterator()
	 */
	@SuppressWarnings("rawtypes")
	public Iterator getElementsByCondition(final Condition condition, final int nbOfElements) {
		return new Iterator(){
			
			private List<Placeable> allObjectsOnBoard = getAllObjectsOnThisBoard();
			private List<Placeable> filteredList = new ArrayList<Placeable>();
			private boolean filteredListCreated = false;
			private int nbOfElementsReturned = 0;
			private int nbOfElementsDesired = nbOfElements;
			private boolean errorInIterator = false;
			private boolean noElementsOnBoard = false;
			
			/**
			 * Create the filtered list for this iterator. Returns true if a list was successfully made, otherwise returns false.
			 * If false is returned, actually a list did get made but it will be empty at all times.
			 * 
			 * @return	| 1 if successfully created list, it could still be empty if no placeable matches the given condition.
			 * 			| 0 if there are no objects on the board.
			 * 			| -1 if something went wrong
			 */
			private int createFilteredList(){
				int	success = -1;
				int size = allObjectsOnBoard.size();
				int i = 0;
				if(size==0){
					success = 0;
				}
				else if(condition == null && size>0){
					success = 1;
					while(i<size && i<nbOfElementsDesired){
						Placeable p = allObjectsOnBoard.get(i);
							filteredList.add(p);
						i++;
					}
				}
				else if(size>0){
					success = 1;
					while(i<size && i<nbOfElementsDesired){
						Placeable p = allObjectsOnBoard.get(i);
						if(condition.validate(p)){
							filteredList.add(p);
						}
						i++;
					}
				}
				return success;
			}
			
			/**
			 * This method returns true if there is a next element that the iterator could deliver.
			 * It returns false in the following cases:
			 * 	- There is no next element.
			 * 		- Because there is no next element that satisfies the given condition.
			 * 		- Because the number of requested placeables has been reached.
			 * 	- There exists an error in the iterator (erroneous parameters given).
			 * 	- There are no elements on the board that this iterator belongs to.
			 */
			@Override
			public boolean hasNext() {
				if(!errorInIterator){
					if(!noElementsOnBoard){
						if(!filteredListCreated){
							int success = createFilteredList();
							if(success == -1){
								errorInIterator=true;
								System.out.println("Error in Iterator: something went wrong with the condition and/or number of elements asked.");
								return false;
							}
							else if(success == 0){
								noElementsOnBoard = true;
								System.out.println("No elements on board so there will never be a next placeable.");
								return false;
							}
							else{
								filteredListCreated = true;
							}
						}
						boolean result = false;
						if(nbOfElementsReturned<filteredList.size()){
							result = true;
						}
						return result;
					}
					else{
						System.out.println("There are no elements on the board so there will never be a next placeable.");
						return false;
					}
				}
				else{
					System.out.println("Error in Iterator: something went wrong with the condition and/or number of elements asked.");
					return false;
				}
			}

			/**
			 * @throws 		IllegalStateException
			 * 				- When the user tried to call the next() method while there is no next item.
			 * 				- When an error exists in the iterator.
			 * 				- When there are no placeables on the board for which an iterator is asked (hasNext()==false!), and still the next() method is called.
			 * 				hasNext()==false || errorInIterator==true || noElementsOnBoard==true || createFilteredList()==-1 || createFilteredList()==0
			 */
			@Override
			public Object next() throws IllegalStateException {
				if(!errorInIterator){
					if(!noElementsOnBoard){
						if(!filteredListCreated){
							int success = createFilteredList();
							if(success == -1){
								errorInIterator=true;
								System.out.println("Error in Iterator: something went wrong with the condition and/or number of elements asked.");
								throw new IllegalStateException();
							}
							else if(success == 0){
								noElementsOnBoard = true;
								System.out.println("No elements on board so cannot get next placeable.");
								throw new IllegalStateException();
							}
							else{
								filteredListCreated = true;
							}
						}
						if(hasNext()){
							nbOfElementsReturned++;
							return filteredList.get(nbOfElementsReturned-1);
						}
						else{
							throw new IllegalStateException();
						}
					}
					else{
						System.out.println("There are no elements on the board so cannot get a next placeable. You should always check if there is a next element with" +
								"the method hasNext(), before calling this method.");
						throw new IllegalStateException();
					}
				}
				else{
					System.out.println("Error in Iterator: something went wrong with the condition and/or number of elements asked.");
					throw new IllegalStateException();
				}
			}

			@Override
			public void remove() throws UnsupportedOperationException {
				throw new UnsupportedOperationException();
			}
			
		};
	}
	
	/**
	 * Returns an iterator, with the given parameters.
	 * 
	 * @param 	condition
	 * 			Condition which the elements should satisfy
	 * @effect	| getElementsByCondition(condition, this.getAllObjectsOnThisBoard().size())
	 */
	@SuppressWarnings("rawtypes")
	public Iterator getElementsByCondition(final Condition condition){
		return getElementsByCondition(condition, this.getAllObjectsOnThisBoard().size());
	}
	
	/**
	 * Returns an iterator, with the given parameters.
	 * 
	 * @param 	nbOfElements
	 * 			The number of elements you want to get from this iterator
	 * @effect	| getElementsByCondition(null, nbOfElements)
	 */
	@SuppressWarnings("rawtypes")
	public Iterator getElementsByCondition(final int nbOfElements){
		return getElementsByCondition(null, nbOfElements);
	}
	
	/**
	 * Returns an iterator, with the given parameters.
	 * 
	 * @effect	| getElementsByCondition(condition, this.getAllObjectsOnThisBoard().size())
	 */
	@SuppressWarnings("rawtypes")
	public Iterator getElementsByCondition(){
		return getElementsByCondition(null, this.getAllObjectsOnThisBoard().size());
	}
}
